package com.andnnl.list;

/**
 * Created by chenss on 2024/1/3.
 */
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class IPDomainWhitelistMatcher2 {

    private final TrieNode root;

    public IPDomainWhitelistMatcher2(Set<String> ipDomainWhitelist) {
        root = new TrieNode();
        for (String ipOrDomain : ipDomainWhitelist) {
            insert(ipOrDomain);
        }
    }

    public boolean isWhitelisted(String ipOrDomain) {
        return search(ipOrDomain, 0, root);
    }

    private void insert(String ipOrDomain) {
        TrieNode node = root;
        for (char c : ipOrDomain.toCharArray()) {
            if (!node.containsKey(String.valueOf(c))) {
                node.put(String.valueOf(c), new TrieNode());
            }
            node = node.get(String.valueOf(c));
        }
        node.setEnd();
    }

    private boolean search(String ipOrDomain, int index, TrieNode node) {
        if (index == ipOrDomain.length()) {
            return node.isEnd();
        }
        char c = ipOrDomain.charAt(index);
        if (c == '*') {
            return searchWildcard(ipOrDomain, index, node);
        } else {
            if (!node.containsKey(String.valueOf(c))) {
                return false;
            }
            return search(ipOrDomain, index + 1, node.get(String.valueOf(c)));
        }
    }

    private boolean searchWildcard(String ipOrDomain, int index, TrieNode node) {
        if (index == ipOrDomain.length() - 1) {
            return true;
        }
        char nextChar = ipOrDomain.charAt(index + 1);
        if (nextChar == '*') {
            return searchWildcard(ipOrDomain, index + 1, node);
        } else {
            for (Map.Entry<String, TrieNode> entry : node.entrySet()) {
                if (entry.getKey().equals("$")) {
                    continue;
                }
                if (search(ipOrDomain, index + 1, entry.getValue())) {
                    return true;
                }
            }
            return false;
        }
    }

    private static class TrieNode extends HashMap<String, TrieNode> {
        private boolean isEnd;

        public void setEnd() {
            isEnd = true;
            put("$", null);
        }

        public boolean isEnd() {
            return isEnd;
        }

        @Override
        public String toString() {
            entrySet().forEach(et-> System.out.println("key:"+et.getKey()+" value:"+et.getValue().toString()));
            return "TrieNode{" +
                    "isEnd=" + isEnd +
                    ",keySet=" +
                    '}';

        }
    }

    @Override
    public String toString() {
        return "IPDomainWhitelistMatcher2{" +
                "root=" + root.toString() +
                '}';
    }
}